package com.chukun.netty.nio;

import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author chukun
 * java原生nio服务端
 */
public class NIOServer {

    private static final int PORT=8899;
    private static Map<String, Channel> channelMap = new ConcurrentHashMap<>();

    /**
     * java 原生的nio服务端程序
     */
    private void server(){
        try {
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            //设置channel为非阻塞模式
            serverSocketChannel.configureBlocking(false);
            ServerSocket serverSocket = serverSocketChannel.socket();
            serverSocket.bind(new InetSocketAddress(PORT));
            System.out.println("server start on port :"+PORT);
            Selector selector = Selector.open();
            //接受客户端连接
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
            while(true) {
                selector.select();
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                Iterator<SelectionKey> iterator = selectionKeys.iterator();
                while (iterator.hasNext()) {
                    SelectionKey selectionKey = iterator.next();
                    SocketChannel socketChannel;
                    if (!selectionKey.isValid()) {
                        System.out.println("接受监听的key不合法");
                        //移除监听的key
                        iterator.remove();
                        break;
                    }
                    //监听连接事件
                    if (selectionKey.isAcceptable()) {
                        ServerSocketChannel channel = (ServerSocketChannel) selectionKey.channel();
                        socketChannel = channel.accept();
                        socketChannel.configureBlocking(false);
                        //连接成功，监听读事件
                        socketChannel.register(selector, SelectionKey.OP_READ);
                        UUID uuid = UUID.randomUUID();
                        String mapKey = "[" + uuid.toString().replaceAll("-", "") + "]";
                        channelMap.put(mapKey, socketChannel);
                        //移除监听的key
                        iterator.remove();
                    } else if (selectionKey.isReadable()) {
                        socketChannel = (SocketChannel) selectionKey.channel();
                        ByteBuffer buffer = ByteBuffer.allocate(1024);
                        int read = socketChannel.read(buffer);
                        if (read > 0) {
                            buffer.flip();
                            Charset charset = Charset.forName("utf-8");
                            String readMessage = new String(charset.decode(buffer).array());
                            System.out.println("received message : " + readMessage);
                            String currentChannelKey="";
                            for(Map.Entry<String,Channel> entry:channelMap.entrySet()){
                                if(entry.getValue()==socketChannel){
                                    currentChannelKey =entry.getKey();
                                    break;
                                }
                            }
                            //获取当前写数据的socketChannel的key
                            for (Map.Entry<String, Channel> entry : channelMap.entrySet()) {
                                SocketChannel sc = (SocketChannel) entry.getValue();
                                ByteBuffer writtenBuf = ByteBuffer.allocate(1024);
                                writtenBuf.put((currentChannelKey+" "+readMessage).getBytes());
                                writtenBuf.flip();
                                sc.write(writtenBuf);
                            }
                        }
                    }
                }
            }
        }catch (Exception ex){
            ex.printStackTrace();
        }
    }

    public static void main(String[] args) {
        new NIOServer().server();
    }
}
